/**
 * 
 */
package qy.jalgotrade.utils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.tuple.Pair;

/**
 * @author qy
 *
 */
public final class PySpecs {

	public interface Len {

		int __len__();
	}

	public static int len(Len obj) {

		return obj.__len__();
	}

	public interface Contains<T> {

		boolean __contains__(T val);
	}

	public static <T> boolean in(Contains<T> obj, T val) {

		return obj.__contains__(val);
	}

	public interface Iter<T> {

		Iterator<T> __iter__();
	}

	public static <T> Iterator<T> iter(Iter<T> obj) {

		return obj.__iter__();
	}

	public interface SeqGetItem<T> extends Len {

		T __getitem__(int idx);
	}

	public static <T> T getitem(SeqGetItem<T> seq, int idx) {

		return seq.__getitem__(idx);
	}

	public interface SeqSetItem<T> extends Len {

		void __setitem__(int idx, T val);
	}

	public <T> void setitem(SeqSetItem<T> seq, int idx, T val) {

		seq.__setitem__(idx, val);
	}

	public interface SeqDelItem {

		void __delitem__(int idx);
	}

	public static <T> List<T> slice(SeqGetItem<T> seq, int from, int to) {

		return slice(seq, from, to, 1);
	}

	public static <T> List<T> slice(SeqGetItem<T> seq, int from, int to, int step) {

		List<T> ret = new ArrayList<>();
		if (from < 0) {
			from = seq.__len__() + from;
		}
		if (to < 0) {
			to = seq.__len__() + 1 + to;
		}

		for (int i = from; i < to; i += step) {
			ret.add(seq.__getitem__(i));
		}
		return ret;
	}

	public static <T> T[] toArray(SeqGetItem<T> seq, int from, int to) {

		if (from < 0) {
			from = seq.__len__() + from;
		}
		if (to < 0) {
			to = seq.__len__() + 1 + to;
		}

		@SuppressWarnings("unchecked")
		T[] ret = (T[]) new Object[to - from];
		for (int i = from; i < to; i++) {
			ret[i] = seq.__getitem__(i);
		}
		return ret;
	}

	public static <T> Object toPrimitiveArray(SeqGetItem<T> seq, int from, int to) {

		Object ret = null;
		Object e = seq.__getitem__(0);
		if (e == null) {
			return ret;
		}

		if (from < 0) {
			from = seq.__len__() + from;
		}
		if (to < 0) {
			to = seq.__len__() + 1 + to;
		}

		Class<?> elemType = e.getClass();
		if (Byte.class.equals(elemType) || Byte.TYPE.equals(elemType)) {
			ret = new byte[to - from];
			for (int i = from; i < to; i++) {
				((byte[]) ret)[i] = (Byte) seq.__getitem__(i);
			}
		} else if (Short.class.equals(elemType) || Short.TYPE.equals(elemType)) {
			ret = new short[to - from];
			for (int i = from; i < to; i++) {
				((short[]) ret)[i] = (Short) seq.__getitem__(i);
			}
		} else if (Integer.class.equals(elemType) || Integer.TYPE.equals(elemType)) {
			ret = new int[to - from];
			for (int i = from; i < to; i++) {
				((int[]) ret)[i] = (Integer) seq.__getitem__(i);
			}
		} else if (Long.class.equals(elemType) || Long.TYPE.equals(elemType)) {
			ret = new long[to - from];
			for (int i = from; i < to; i++) {
				((long[]) ret)[i] = (Long) seq.__getitem__(i);
			}
		} else if (Float.class.equals(elemType) || Float.TYPE.equals(elemType)) {
			ret = new float[to - from];
			for (int i = from; i < to; i++) {
				((float[]) ret)[i] = (Float) seq.__getitem__(i);
			}
		} else if (Double.class.equals(elemType) || Double.TYPE.equals(elemType)) {
			ret = new double[to - from];
			for (int i = from; i < to; i++) {
				((double[]) ret)[i] = (Double) seq.__getitem__(i);
			}
		}
		return ret;
	}

	public interface MapGetItem<K, V> {

		V __getitem__(K key);
	}

	public static <K, V> V getitem(MapGetItem<K, V> map, K key) {

		return map.__getitem__(key);
	}

	public interface MapSetItem<K, V> {

		void __setitem__(K key, V val);
	}

	public <K, V> void setitem(MapSetItem<K, V> map, K key, V val) {

		map.__setitem__(key, val);
	}

	public interface MapDelItem<K, V> {

		void __delitem__(K key);
	}

	public interface ReadOnlySeq<T> extends Contains<T>, SeqGetItem<T>, Iter<T> {

	}

	public interface ReadWriteSeq<T> extends ReadOnlySeq<T>, SeqSetItem<T>, SeqDelItem {

	}

	public interface ReadOnlyMap<K, V> extends Len, Contains<K>, MapGetItem<K, V>, Iter<Pair<K, V>> {

	}

	public interface ReadWriteMap<K, V> extends ReadOnlyMap<K, V>, MapSetItem<K, V>, MapDelItem<K, V> {

	}
}
